#pragma once

#include <windows.h>
#ifdef _DEBUG
#undef  _DEBUG
	#include <map>
	#include <vector>
	#include <Python.h>
#define _DEBUG
#else
	#include <map>
	#include <vector>
	#include <Python.h>
#endif
#include "AABB.h"

struct AES_KEYTYPE16
{
	short keys[16];
};

struct BlockNode
{
	AES_KEYTYPE16 *mData;
	BlockNode* mNext;
};

class BreakKey: public IAABBHost
{
private:
	static BreakKey* msInstance;
private:
	std::map<int, int> mKeyValues;
	std::string mPlainText;
	std::vector<std::string> mDebugMsgs;
	std::vector<std::string> mCmds;
	IAABB* mAABB;
	int mBatchCount;
	int mMaxBatch;
	AES_KEYTYPE16 mAes[1000];
	int mAesCount;
	volatile DWORD mNodeCount, mFreeNodeCount;
	CRITICAL_SECTION mLock;
	CRITICAL_SECTION mLockCurr;
	CRITICAL_SECTION mLockFree;
	CRITICAL_SECTION mLockDebugOut;
	CRITICAL_SECTION mLockCmd;
	BlockNode *mTopNode, *mBotNode;
	BlockNode *mCurrNode;
	int mCurrCount;
	BlockNode *mFreeTopNode, *mFreeBotNode;
	DWORD mLastNewAABBTick, mLastRunTick;
	BreakKey();
public:
	static BreakKey* Instance()
	{
		if (!msInstance)
		{
			msInstance = new BreakKey();
		}
		return msInstance;
	}

	void Init();
	void Uninit();
	void Run();
	bool ExecuteScript(const char* szScriptFile);
	void SetV(int iKey, int iValue);
	int GetV(int iKey);
	void SetPlainText(const std::string& strPlainText);
	IAABB* AABB();
	std::string GetPlainText();
	BlockNode* PopBlockNode();
	void FreeBlockNode(BlockNode* node);
	AES_KEYTYPE16* GetAes() { return mAes; };
	int GetAesCount() { return mAesCount;};
	void AddAes(const char* szAes);
	void DebugOut(const char * _Format, ...);
	void RunDebugOut();
	void PushCmd(const char *szCmd);
private:
	BlockNode* GetBlockNode();
	virtual void __stdcall NewAABB(const char* szAABB, int nLen, int nCount);
};